/*****************************************************
 * Copyright ?, 2006-2008 Huawei Technologies Co.,Ltd. 
 * Filename: halsurf.cpp
 * Version: 1.0 / Author: Lei Yu / Date: 2007-4-27
 * Description: 
 * Version: 
 * Function List :
 * History:
 * leiyu    2007-4-27   1.0  create this file
 ****************************************************/
 
#include "precomp.h"

#ifdef DD_ENABLE

typedef struct {
    LPDDRAWI_DDRAWSURFACE_LCL pSrcSurf;
    DWORD       dwID;    /* 0 if available */
    DWORD       dwDstX;
    DWORD       dwDstY;
    DWORD       dwDstW;
    DWORD       dwDstH;
    DWORD       dwSrcX;
    DWORD       dwSrcY;
    DWORD       dwSrcW;    
    DWORD       dwSrcH;
    DWORD       pSrcStart;
    DWORD       dwSrcPitch;
    DWORD       dwSurfBpp;
    DWORD       dwYPlaneSize;
    DWORD       dwUVPlaneSize;
    /* Hardware-Used stuffs */
    WORD        wVidEngNo;
    WORD        dwVideoFmt;
    WORD        wVideoCtrl;
    WORD        wVFIFO;
    WORD        wFetch;
} OVERLAYSURF,FAR *LPOVERLAYSURF;

OVERLAYSURF os, osrotate;

#ifdef FULLSCREEN
bool gFullScreen = 0;
extern DISPLAY_ARGS gHisiArgs[1];
#endif

BOOL        gAngle270 = FALSE;

#define OVERLAY_WMP_EVENT       TEXT("Global\\Overlay_Wmp_Event")

/*****************************************************
 * Function: HalFlip
 * Description: swaps the surface memory of the back 
 *              buffer with the surface memory of the 
 *              front buffer.
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: pd - Pointer to a DDHAL_FLIPDATA structure 
 *             that the driver uses to perform a flip
 * Output: NONE
 * Return: 
 * Others: NONE
 ****************************************************/
DWORD WINAPI HalFlip( LPDDHAL_FLIPDATA pd )
{
    return ((HisiDisp *)GetDDGPE())->Flip(pd);
}

/*****************************************************
 * Function: Flip
 * Description: swaps the surface memory of the back 
 *              buffer with the surface memory of the 
 *              front buffer.
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: pd - Pointer to a DDHAL_FLIPDATA structure 
 *             that the driver uses to perform a flip
 * Output: NONE
 * Return: 
 * Others: NONE
 ****************************************************/
DWORD HisiDisp::Flip(LPDDHAL_FLIPDATA pd)
{
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("+HalFlip\r\n")));
    DWORD dwRegValue;

    if (pd->dwFlags & DDFLIP_WAITNOTBUSY)
    {
        WaitForNotBusy();
    }
    else if (IsBusy())
    {
        DEBUGMSG(GPE_ZONE_HISI,(TEXT("Graphics engine busy\r\n")));

        pd->ddRVal = DDERR_WASSTILLDRAWING;
        return DDHAL_DRIVER_HANDLED;
    }
    
	if ((pd->dwFlags & DDFLIP_WAITVSYNC)
        && (pd->lpSurfCurr->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
	{
	    DWORD dwTimeoutValue = GetTickCount() + 500;
	    do
	    {
	        if(_memrD_EDCreg(EDC_STS) & BAS_VSYNC_MASK)
	        {
	            break;
	        }
	    }while (GetTickCount() < dwTimeoutValue);
	}
	
    HisiSurf* surfTarg = (HisiSurf *)DDGPESurf::GetDDGPESurf(pd->lpSurfTarg);
    
    if (pd->lpSurfCurr->ddsCaps.dwCaps & DDSCAPS_OVERLAY)
    {
        DDGPESurf* surfCurr = DDGPESurf::GetDDGPESurf(pd->lpSurfCurr);
        if (surfCurr == m_pVisibleOverlay)
        {            
            switch (surfTarg->PixelFormat())
            {
            case ddgpePixelFormat_YUY2422:
            case ddgpePixelFormat_UYVY422:    
            case ddgpePixelFormat_5550:
            case ddgpePixelFormat_565:            
                //if (!(m_iRotate == DMDO_270))
                if (!gAngle270)
                {
                    _memwD_EDCreg(EDC_YRGB_ADDR, surfTarg->GetPhysicalAddress() + 
                                                 (osrotate.dwSrcY * surfTarg->Stride()) +
                                                 osrotate.dwSrcX * 2);
                }
                /* rotate 270, we should config address of first pixsel of last row */
                else
                {
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 surfTarg->Stride() * (surfTarg->Height() - 1);
                    _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
                }
                _memwD_EDCreg(EDC_VIDEO_LN_OFFSET, surfTarg->Stride() & YRGB_LN_OFFSET_MASK);
                break;
            case ddgpePixelFormat_8880:
                //if (!(m_iRotate == DMDO_270))
                if (!gAngle270)
                {
                    _memwD_EDCreg(EDC_YRGB_ADDR, surfTarg->GetPhysicalAddress() + 
                                                 (osrotate.dwSrcY * surfTarg->Stride()) +
                                                 osrotate.dwSrcX * 4);
                }
                /* rotate 270, we should config address of first pixsel of last row */
                else
                {
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 surfTarg->Stride() * (surfTarg->Height() - 1);
                    _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
                }
                _memwD_EDCreg(EDC_VIDEO_LN_OFFSET, surfTarg->Stride() & YRGB_LN_OFFSET_MASK);
                break;
            case ddgpePixelFormat_CustomFormat:
                //if (!(m_iRotate == DMDO_270))
                if (!gAngle270)
                {
                    /* Y address */
                    dwRegValue = surfTarg->GetPhysicalAddress() +
                                 (osrotate.dwSrcY * surfTarg->Stride()) +
                                 osrotate.dwSrcX;
                    _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
                    
                    /* UV address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 surfTarg->Stride() * AlignTo(surfTarg->Height(), 2) +
                                 ((osrotate.dwSrcY / 2) * surfTarg->Stride()) +
                                 osrotate.dwSrcX;
                    _memwD_EDCreg(EDC_UV_ADDR, dwRegValue);
                    
                }
                /* rotate 270, we should config address of first pixsel of last row */
                else
                {
                     /* Y address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                surfTarg->Stride() * (surfTarg->Height() - 1);
                    _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
                    
                    /* UV address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 surfTarg->Stride() * surfTarg->Height() + 
                                 surfTarg->Stride() * (surfTarg->Height() / 2 - 1);
                    _memwD_EDCreg(EDC_UV_ADDR, dwRegValue);
                }
                _memwD_EDCreg(EDC_VIDEO_LN_OFFSET, surfTarg->Stride() & YRGB_LN_OFFSET_MASK);
                break;    
                
            case ddgpePixelFormat_YV12:            
                //if (!(m_iRotate == DMDO_270))    
                if (!gAngle270)
                {
                    /* Y address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 (osrotate.dwSrcY * surfTarg->Stride()) +
                                 osrotate.dwSrcX;
                    _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
                    
                    /* V address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 surfTarg->Stride() * AlignTo(surfTarg->Height(), 2) + 
                                 ((osrotate.dwSrcY / 2)  * (surfTarg->Stride() / 2)) +
                                 osrotate.dwSrcX / 2;
                    _memwD_EDCreg(EDC_V_ADDR, dwRegValue);

                    /* U address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 surfTarg->Stride() * AlignTo(surfTarg->Height(), 2) +
                                 (surfTarg->Stride() / 2) * (AlignTo(surfTarg->Height(), 2) / 2) +
                                 ((osrotate.dwSrcY / 2)  * (surfTarg->Stride() / 2)) +
                                 osrotate.dwSrcX / 2;
                    _memwD_EDCreg(EDC_UV_ADDR, dwRegValue);
                }
                /* rotate 270, we should config address of first pixsel of last row */        
                else
                {
                     /* Y address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                surfTarg->Stride() * (surfTarg->Height() - 1);
                    _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
                    
                    /* V address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 surfTarg->Stride() * AlignTo(surfTarg->Height(), 2) + 
                                 (surfTarg->Stride() / 2) * (surfTarg->Height() / 2 - 1);
                    _memwD_EDCreg(EDC_V_ADDR, dwRegValue);

                    /* U address */
                    dwRegValue = surfTarg->GetPhysicalAddress() + 
                                 surfTarg->Stride() * surfTarg->Height() +
                                 (surfTarg->Stride() / 2) * (AlignTo(surfTarg->Height(), 2) / 2) +
                                 (surfTarg->Stride() / 2) * (surfTarg->Height() / 2 - 1);
                    _memwD_EDCreg(EDC_UV_ADDR, dwRegValue);
                }                

                _memwD_EDCreg(EDC_VIDEO_LN_OFFSET, surfTarg->Stride() & YRGB_LN_OFFSET_MASK);
                break;
                
            default:
                DISPMSG(GPE_ZONE_HISI, (TEXT("Error: Unexpected overlay format!\r\n")));
                pd->ddRVal = DDERR_UNSUPPORTED;
                return DDHAL_DRIVER_HANDLED;
            }
            
            m_pVisibleOverlay = surfTarg;
        }
        else
        {
            pd->ddRVal = DDERR_OUTOFCAPS;
            return DDHAL_DRIVER_HANDLED;
        }

    }
    else if (pd->lpSurfCurr->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
    {
        SetPrimarySurface((GPESurf *)surfTarg, (pd->dwFlags & DDFLIP_WAITVSYNC));
    }
    else
    {
        pd->ddRVal = DDERR_OUTOFCAPS;
        return DDHAL_DRIVER_HANDLED;
    }
    
    pd->ddRVal = DD_OK;

    return DDHAL_DRIVER_HANDLED;
}

/*****************************************************
 * Function: HalGetBltStatus
 * Description: determines whether the blit queue has 
 *              room for more blits and whether the blit 
 *              queue is busy.
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: pd - Pointer to a DDHAL_GETBLTSTATUSDATA 
 *             structure that returns the blit's status 
 *             information.
 * Output: NONE
 * Return: 
 * Others: NONE
 ****************************************************/
DWORD WINAPI HalGetBltStatus(LPDDHAL_GETBLTSTATUSDATA pd)
{
    DEBUGENTER(HalGetBltStatus);

    pd->ddRVal = DD_OK;

    if (pd->dwFlags & (DDGBS_CANBLT | DDGBS_ISBLTDONE))
    {
        if (((HisiDisp *)GetDDGPE())->IsBusy())
        {
            pd->ddRVal = DDERR_WASSTILLDRAWING;
        }
    }
    
    return DDHAL_DRIVER_HANDLED;
}

/*****************************************************
 * Function: HalGetFlipStatus
 * Description: whether the surface has finished flipping.
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: pd - Pointer to a DDHAL_GETFLIPSTATUSDATA 
 *             structure that the driver uses to determine 
 *             whether a previous flip has finished so 
 *             that the current flip can proceed.
 * Output: NONE
 * Return: 
 * Others: NONE
 ****************************************************/

DWORD WINAPI HalGetFlipStatus(LPDDHAL_GETFLIPSTATUSDATA pd)
{
    DEBUGENTER(HalGetFlipStatus);
    
    pd->ddRVal = DDERR_UNSUPPORTED;

    return DDHAL_DRIVER_HANDLED;
}

#define DDOVER_ALPHA \
    (DDOVER_ALPHASRC | \
     DDOVER_ALPHADEST | \
     DDOVER_ALPHACONSTOVERRIDE)

#define DDOVER_KEY \
    (DDOVER_KEYSRC | \
     DDOVER_KEYSRCOVERRIDE |\
     DDOVER_KEYDEST | \
     DDOVER_KEYDESTOVERRIDE)

#define KEYING          0x1
#define BLENDING        0x2
#define OPAQUEING       0x4

/*****************************************************
 * Function: HalUpdateOverlay
 * Description: repositions or modifies the visual 
 *              attributes of an overlay surface.
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: pd - Pointer to a DDHAL_UPDATEOVERLAYDATA 
 *             structure that the driver uses to update 
 *             the overlay surface.
 * Output: NONE
 * Return: 
 * Others: NONE
 ****************************************************/
DWORD WINAPI HalUpdateOverlay(LPDDHAL_UPDATEOVERLAYDATA pd)
{
    DEBUGENTER(HalUpdateOverlay);

    return ((HisiDisp *)GetDDGPE())->UpdateOverlay(pd);
}

/*****************************************************
 * Function: HalSetOverlayPosition
 * Description: changes the display coordinates of an 
 *              overlay surface.
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: pd - Pointer to a DDHAL_UPDATEOVERLAYDATA 
 *             structure that the driver uses to update 
 *             the overlay surface.
 * Output: NONE
 * Return: 
 * Others: NONE
 ****************************************************/
DWORD WINAPI HalSetOverlayPosition(LPDDHAL_SETOVERLAYPOSITIONDATA pd)
{
    DEBUGENTER( HalSetOverlayPosition );

    return ((HisiDisp *)GetDDGPE())->SetOverlayPosition(pd);
}

/*****************************************************
 * Function: HalSetColorKey
 * Description: sets the color-key value for the 
 *              specified surface.
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: pd - Pointer to a DDHAL_SETCOLORKEYDATA 
 *             structure that the driver uses to set 
 *             the color-key value for the specified surface.
 * Output: NONE
 * Return: 
 * Others: NONE
 ****************************************************/
DWORD WINAPI HalSetColorKey(LPDDHAL_SETCOLORKEYDATA pd)
{
    DEBUGENTER(HalSetColorKey);

    return ((HisiDisp *)GetDDGPE())->SetColorKey(pd);
}

DWORD HisiDisp::SetColorKey(LPDDHAL_SETCOLORKEYDATA pd)
{
    DDGPESurf* pSurf = DDGPESurf::GetDDGPESurf(pd->lpDDSurface);
    if (pSurf != NULL)
    {
        pSurf->SetColorKeyLow(pd->ckNew.dwColorSpaceLowValue);
        pSurf->SetColorKeyHigh(pd->ckNew.dwColorSpaceHighValue);
        pd->ddRVal = DD_OK;
    }
    else
    {
        pd->ddRVal = DDERR_INVALIDOBJECT;
    }
    
    return DDHAL_DRIVER_HANDLED;
}

DWORD HisiDisp::UpdateOverlay(LPDDHAL_UPDATEOVERLAYDATA pd)
{
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("HisiDisp::+UpdateOverlay\r\n")));
    /*
    DDGPESurf*  pSrcSurf;
    DDGPESurf*  pDstSurf;
    */
    HisiSurf*   pSrcSurf;
    HisiSurf*   pDstSurf;
    DWORD       dwRegValue;
    DWORD       dwVideoAngle = 0;
    //DWORD       dwStartAdd;
    DWORD       dwControl;
    DWORD       dwColorKeyLow;
    DWORD       dwColorKeyHigh;
    BOOL        bSrcColorKey;
    BOOL        bPacked;
    BOOL        bRGB888;
    STATUS_CODE ret = HIPM_STATUS_SUCCESS;
    
    pSrcSurf = (HisiSurf *)DDGPESurf::GetDDGPESurf(pd->lpDDSrcSurface);
    pDstSurf = (HisiSurf *)DDGPESurf::GetDDGPESurf(pd->lpDDDestSurface);
    
    /* error if requested both keying and blending */
    if ((pd->dwFlags & DDOVER_KEY) && (pd->dwFlags & DDOVER_ALPHA))
    {
        DISPMSG(GPE_ZONE_HISI, (TEXT("Error: can't handle both keying and blending!\r\n")));
        pd->ddRVal = DDERR_INVALIDPARAMS;
        return DDHAL_DRIVER_HANDLED;
    }
    
    if (pd->dwFlags & DDOVER_HIDE)
    {
        if (pSrcSurf == m_pVisibleOverlay)
        {
            /* hide the visible overlay */
            m_pVisibleOverlay = NULL;
#if 0
            dwRegValue = _memrD_EDCreg(EDC_INTS);
            dwRegValue &= ~(1 << 4);
            _memwD_EDCreg(EDC_INTS, dwRegValue);
            
            do
            {
                if(_memrD_EDCreg(EDC_INTS) & (1 << 4))
                {
                    break;
                }
            }while (1);
#endif

            dwRegValue = _memrD_EDCreg(EDC_VIDEO_CTL);
            _memwD_EDCreg(EDC_VIDEO_CTL, dwRegValue & ~VIDEO_ENABLE);

            if (m_hOverlayWmp)
            {
                CloseHandle(m_hOverlayWmp);
                m_hOverlayWmp = NULL;
            }
            
            if (HIPM_INVALID_CL_ID != m_ClientId)
            {
                if (IsNeedLockProfile(osrotate.dwSrcW, osrotate.dwSrcH, 
                                        osrotate.dwDstW, osrotate.dwDstH))
                {
                    ret = HiPM_ReleaseFreqBlock(m_ClientId);
                    
                    if (HIPM_STATUS_SUCCESS != ret)
                    {
                        NKDbgPrintfW(_T("-------HiPM_ReleaseFreqBlock Failed: %d!!!\r\n"), ret);
                    }
                }
                else
                {
                    ret = HiPM_ReleaseMinProfile(m_ClientId);
        
                    if (HIPM_STATUS_SUCCESS != ret)
                    {
                        NKDbgPrintfW(_T("-------HiPM_ReleaseMinProfile Failed: %d!!!\r\n"), ret);
                    }
                }
                
                ret = HiPM_DeRegister(m_ClientId);
                
                if (HIPM_STATUS_SUCCESS != ret)
                {
                    NKDbgPrintfW(_T("-------HiPM_DeRegister Failed: %d!!!\r\n"), ret);
                }
                else
                {
                    m_ClientId = HIPM_INVALID_CL_ID;
                }
            }
            //_memwD_EDCreg(EDC_VIDEO_CTL, 0);
#if 0
            //RETAILMSG(1, (TEXT("EDC disable start!\r\n")));
            do
            {
                if(0 == (_memrD_EDCreg(EDC_VIDEO_CTL) & VIDEO_ENABLE))
                {
                    break;
                }
            }while (1);
#endif            
        }
        else
        {
            /* the overlay is not currently visible
               nothing we need to do here */
            DEBUGMSG(GPE_ZONE_HISI, (TEXT("The overlay to hide is not the one to display.\r\n")));            
        }

        pd->ddRVal = DD_OK;
        return DDHAL_DRIVER_HANDLED;
    }

    if (pSrcSurf != m_pVisibleOverlay)
    {
        if (pd->dwFlags & DDOVER_SHOW)
        {
            DEBUGMSG(GPE_ZONE_HISI, (TEXT("HisiDisp::OVERLAY SHOW REQUEST\r\n")));
            if (m_pVisibleOverlay != NULL)
            {
                /* some other overlay is already visible */
                DISPMSG(GPE_ZONE_HISI, (TEXT("Error: Other overlay already visible!\r\n")));
                pd->ddRVal = DDERR_OUTOFCAPS;
                return DDHAL_DRIVER_HANDLED;
            }
            else
            {
                /* we are going to make the overlay visible
                   so mark it as such: */
                m_pVisibleOverlay = pSrcSurf;
                DEBUGMSG(GPE_ZONE_HISI, (TEXT("HisiDisp::OVERLAY SHOW\r\n")));              
            }
        }
        else /* DDOVER_SHOW not requested */
        {
            /* the overlay isn't visible, and we haven't been
               asked to make it visible, so nothing we need to do */
            pd->ddRVal = DD_OK;
            return DDHAL_DRIVER_HANDLED;
        }
    }

    DWORD dwSrcBytesPerPixel = EGPEFormatToBpp[pSrcSurf->Format()] / 8;

    /* 
       if both dst width and height equals to screen size, we know WMP has entered fullscreen mode
       so if width > height, we should switch them.
       this is not the best method, if u find better one, please change it!!!
    */
#ifdef FULLSCREEN
    //RETAILMSG(1, (TEXT("Before read reg!\r\n")));
    GetFullScreenModeFromReg();
    //RETAILMSG(1, (TEXT("After read reg!\r\n")));

    gAngle270 = FALSE;
    
    if (gFullScreen)
    {
        if ((gHisiArgs[MODEID].ScreenWidth == os.dwDstW) 
            && (gHisiArgs[MODEID].ScreenHeight == os.dwDstH))
        {
            os.dwDstH = gHisiArgs[MODEID].ScreenWidth;
            os.dwDstW = gHisiArgs[MODEID].ScreenHeight;
            //dwVideoAngle = VIDEO_ROT_90;
            dwVideoAngle = VIDEO_ROT_270;
            gAngle270 = TRUE;
        }
    }
#if 0
    if ((gHisiArgs[MODEID].ScreenWidth == os.dwDstW) 
        && (gHisiArgs[MODEID].ScreenHeight == os.dwDstH) 
        && (os.dwSrcW > os.dwSrcH))
    {
        os.dwDstH = gHisiArgs[MODEID].ScreenWidth;
        os.dwDstW = gHisiArgs[MODEID].ScreenHeight;
        gFullScreen = 1;
    }
    else
    {
        gFullScreen = 0;
    }
#endif    
#endif
    
    if(!m_hOverlayWmp)
    {
        m_hOverlayWmp = CreateEvent(NULL, TRUE, FALSE, OVERLAY_WMP_EVENT);
    }
    
    /* 
     * OVERLAYSURF memebers should be filled... to be implemented 
     * in the future.We save the logical coordinates 
     * of the overlay here. 
     */
    os.dwDstX = pd->rDest.left;
    os.dwDstY = pd->rDest.top;
    os.dwDstW = pd->rDest.right - pd->rDest.left;
    os.dwDstH = pd->rDest.bottom - pd->rDest.top;
    os.dwSrcX = pd->rSrc.left;
    os.dwSrcY = pd->rSrc.top;
    os.dwSrcW = pd->rSrc.right - pd->rSrc.left;
    os.dwSrcH = pd->rSrc.bottom - pd->rSrc.top;
    os.dwSurfBpp = dwSrcBytesPerPixel;

#ifdef ROTATE
    pSrcSurf->RotateRectl(reinterpret_cast<RECTL *>(&(pd->rSrc)));
    pDstSurf->RotateRectl(reinterpret_cast<RECTL *>(&(pd->rDest)));
#endif
    
    /* BEGIN: Added by leiyu, 2008/02/26   PN:AT4D01036 */
    osrotate.dwDstX = pd->rDest.left;
    osrotate.dwDstY = pd->rDest.top;
    osrotate.dwDstW = pd->rDest.right - pd->rDest.left;
    osrotate.dwDstH = pd->rDest.bottom - pd->rDest.top;
    osrotate.dwSrcX = pd->rSrc.left;
    osrotate.dwSrcY = pd->rSrc.top;
    osrotate.dwSrcW = pd->rSrc.right - pd->rSrc.left;
    osrotate.dwSrcH = pd->rSrc.bottom - pd->rSrc.top;
    /* END:   Added by leiyu, 2008/02/26 */
    
    dwControl = 0;
    bSrcColorKey = 0;
    bPacked = 0;
    bRGB888 = 0;

    switch (pSrcSurf->PixelFormat())
    {
    case ddgpePixelFormat_YUY2422:
        dwControl = dwControl | VIDEO_FMTIN_YUY2; 
        bPacked = 1;
        break;
        
    case ddgpePixelFormat_UYVY422:
        dwControl = dwControl | VIDEO_FMTIN_UYVY;
        bPacked = 1;
        break;        

    case ddgpePixelFormat_YV12:
        dwControl = dwControl | VIDEO_FMTIN_YV12;
        break;

    case ddgpePixelFormat_CustomFormat:
        dwControl = dwControl | VIDEO_FMTIN_NV12;
        break;
        
    case ddgpePixelFormat_5550:
        dwControl = dwControl | VIDEO_FMTIN_RGB555;
        bPacked = 1;
        break;

    case ddgpePixelFormat_565:
        dwControl = dwControl | VIDEO_FMTIN_RGB565;
        bPacked = 1;
        break;

    case ddgpePixelFormat_8880:
        dwControl = dwControl | VIDEO_FMTIN_RGB888;
        bPacked = 1;
        bRGB888 = 1;
        break;

    default:
        DISPMSG(GPE_ZONE_HISI, (TEXT("Error: Unexpected overlay format!\r\n")));
        pd->ddRVal = DDERR_UNSUPPORTED;
        return DDHAL_DRIVER_HANDLED;
    }

    /* see if color key is set */
    if (pd->dwFlags & DDOVER_KEY)
    {
        /* set src color key */
        if (pd->dwFlags & DDOVER_KEYSRC ||
             pd->dwFlags & DDOVER_KEYSRCOVERRIDE)
        {
            if (pd->dwFlags & DDOVER_KEYSRC)
            {
                dwColorKeyLow = pd->lpDDSrcSurface->ddckCKSrcOverlay.dwColorSpaceLowValue;
                dwColorKeyHigh = pd->lpDDSrcSurface->ddckCKSrcOverlay.dwColorSpaceHighValue;
            }
            else
            {
                dwColorKeyLow = pd->overlayFX.dckSrcColorkey.dwColorSpaceLowValue;
                dwColorKeyHigh = pd->overlayFX.dckSrcColorkey.dwColorSpaceHighValue;
            }
#if 0
            if (pSrcSurf->PixelFormat() == ddgpePixelFormat_565)
            {
                /* convert 888 to 565 */
                
                dwColorKeyLow  = (dwColorKeyLow >> 8) & 0xF800 |
                                 (dwColorKeyLow >> 5) & 0x07E0 |
                                 (dwColorKeyLow >> 3) & 0x001F;
                dwColorKeyHigh = (dwColorKeyHigh >> 8) & 0xF800 |
                                 (dwColorKeyHigh >> 5) & 0x07E0 |
                                 (dwColorKeyHigh >> 3) & 0x001F;
                                 
            } 
            else if(pSrcSurf->PixelFormat() == ddgpePixelFormat_5550)
            {
                /* convert 888 to 555 */
                dwColorKeyLow  = (dwColorKeyLow >> 8) & 0x7C00 |
                                 (dwColorKeyLow >> 5) & 0x03E0 |
                                 (dwColorKeyLow >> 3) & 0x001F;
                dwColorKeyHigh = (dwColorKeyHigh >> 8) & 0x7C00 |
                                 (dwColorKeyHigh >> 5) & 0x03E0 |
                                 (dwColorKeyHigh >> 3) & 0x001F;
            }
#endif
            bSrcColorKey = 1;
            _memwD_EDCreg(EDC_VIDEO_COLORK_MIN, 
                        (dwColorKeyLow << VIDEO_COLORK_MIN_SHIFT) & VIDEO_COLORK_MIN_MASK);
            _memwD_EDCreg(EDC_VIDEO_COLORK_MAX, 
                        (dwColorKeyHigh << VIDEO_COLORK_MAX_SHIFT) & VIDEO_COLORK_MAX_MASK);
            dwControl = dwControl | VIDEO_SRC_COLORK_EN;
            /* clear dst color key enable bit */
            dwRegValue = _memrD_EDCreg(EDC_GRP_CTL);
            dwRegValue = dwRegValue & ~(GRP_DES_COLORK_EN) | GRP_TOP;
            _memwD_EDCreg(EDC_GRP_CTL, dwRegValue);
        }

        if (pd->dwFlags & DDOVER_KEYDEST ||
             pd->dwFlags & DDOVER_KEYDESTOVERRIDE)
        {
            /* Set destination color key */
            if (pd->dwFlags & DDOVER_KEYDEST)
            {
                dwColorKeyLow = pd->lpDDDestSurface->ddckCKDestOverlay.dwColorSpaceLowValue;
                dwColorKeyHigh = pd->lpDDDestSurface->ddckCKDestOverlay.dwColorSpaceHighValue;
            }
            else
            {
                dwColorKeyLow = pd->overlayFX.dckDestColorkey.dwColorSpaceLowValue;
                dwColorKeyHigh = pd->overlayFX.dckDestColorkey.dwColorSpaceHighValue;
            }
#if 0
            if (pDstSurf->PixelFormat() == ddgpePixelFormat_565)
            {
                /* convert 888 to 565 */
                
                dwColorKeyLow  = (dwColorKeyLow >> 8) & 0xF800 |
                                 (dwColorKeyLow >> 5) & 0x07E0 |
                                 (dwColorKeyLow >> 3) & 0x001F;
                dwColorKeyHigh = (dwColorKeyHigh >> 8) & 0xF800 |
                                 (dwColorKeyHigh >> 5) & 0x07E0 |
                                 (dwColorKeyHigh >> 3) & 0x001F;
            } 
#endif
            _memwD_EDCreg(EDC_GRP_COLORK_MIN, 
                        (dwColorKeyLow << GRP_COLORK_MIN_SHIFT) & GRP_COLORK_MIN_MASK);
            _memwD_EDCreg(EDC_GRP_COLORK_MAX, 
                        (dwColorKeyHigh << GRP_COLORK_MAX_SHIFT) & GRP_COLORK_MAX_MASK);
            dwRegValue = _memrD_EDCreg(EDC_GRP_CTL);
            dwRegValue = dwRegValue | GRP_DES_COLORK_EN;
            _memwD_EDCreg(EDC_GRP_CTL, dwRegValue);

            /* clear src color key enable bit */
            if(!bSrcColorKey)
            {
                dwControl = dwControl & ~(VIDEO_SRC_COLORK_EN);
            }
        }
    }
    else
    {
        /* if hide old overlay with color key 
           and show new ones without color key, 
           we should clear color key enable bit */
        dwRegValue = _memrD_EDCreg(EDC_GRP_CTL);
        dwRegValue = dwRegValue & ~(GRP_DES_COLORK_EN);
        _memwD_EDCreg(EDC_GRP_CTL, dwRegValue);
        dwControl = dwControl & ~(VIDEO_SRC_COLORK_EN);
    }

#if 0
    switch(m_iRotate)
    {
    case DMDO_0:
        dwVideoAngle = VIDEO_ROT_0;
        break;
    case DMDO_90:
        dwVideoAngle = VIDEO_ROT_90;
        break;
    case DMDO_270:
        dwVideoAngle = VIDEO_ROT_270;
        gAngle270 = TRUE;
        break;
    default:
        dwVideoAngle = VIDEO_ROT_0;        
        break;
    }
#endif

    if(bPacked)
    {
        if (!gAngle270)
        {
            if (!bRGB888)
            {
                _memwD_EDCreg(EDC_YRGB_ADDR, pSrcSurf->GetPhysicalAddress() + 
                                             (osrotate.dwSrcY * pSrcSurf->Stride()) +
                                             osrotate.dwSrcX * 2);
            }
            else
            {
                _memwD_EDCreg(EDC_YRGB_ADDR, pSrcSurf->GetPhysicalAddress() + 
                                             (osrotate.dwSrcY * pSrcSurf->Stride()) +
                                             osrotate.dwSrcX * 4);
            }
        }
        /* rotate 270, we should config address of first pixsel of last row */
        else
        {
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                         pSrcSurf->Stride() * (pSrcSurf->Height() - 1);
            _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
        }
        _memwD_EDCreg(EDC_VIDEO_LN_OFFSET, pSrcSurf->Stride() & YRGB_LN_OFFSET_MASK);
    }
    else if(pSrcSurf->PixelFormat() == ddgpePixelFormat_YV12)
    {
        if (!gAngle270)    
        {
            /* Y address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                         (osrotate.dwSrcY * pSrcSurf->Stride()) +
                         osrotate.dwSrcX;
            _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
            
            /* V address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                         pSrcSurf->Stride() * AlignTo(pSrcSurf->Height(), 2) + 
                         ((osrotate.dwSrcY / 2)  * (pSrcSurf->Stride() / 2)) +
                         osrotate.dwSrcX / 2;
            _memwD_EDCreg(EDC_V_ADDR, dwRegValue);

            /* U address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                         pSrcSurf->Stride() * AlignTo(pSrcSurf->Height(), 2) +
                         (pSrcSurf->Stride() / 2) * (AlignTo(pSrcSurf->Height(), 2) / 2) +
                         ((osrotate.dwSrcY / 2)  * (pSrcSurf->Stride() / 2)) +
                         osrotate.dwSrcX / 2;
            _memwD_EDCreg(EDC_UV_ADDR, dwRegValue);
        }
        /* rotate 270, we should config address of first pixsel of last row */        
        else
        {
             /* Y address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                        pSrcSurf->Stride() * (pSrcSurf->Height() - 1);
            _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
            
            /* V address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                         pSrcSurf->Stride() * AlignTo(pSrcSurf->Height(), 2) + 
                         (pSrcSurf->Stride() / 2) * (pSrcSurf->Height() / 2 - 1);
            _memwD_EDCreg(EDC_V_ADDR, dwRegValue);

            /* U address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                         pSrcSurf->Stride() * pSrcSurf->Height() +
                         (pSrcSurf->Stride() / 2) * (AlignTo(pSrcSurf->Height(), 2) / 2) +
                         (pSrcSurf->Stride() / 2) * (pSrcSurf->Height() / 2 - 1);
            _memwD_EDCreg(EDC_UV_ADDR, dwRegValue);
        }

        _memwD_EDCreg(EDC_VIDEO_LN_OFFSET, pSrcSurf->Stride() & YRGB_LN_OFFSET_MASK);      
    }
    else if (pSrcSurf->PixelFormat() == ddgpePixelFormat_CustomFormat)
    {
        if (!gAngle270)
        {
            /* Y address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() +
                         (osrotate.dwSrcY * pSrcSurf->Stride()) +
                         osrotate.dwSrcX;
            _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
            
            /* UV address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                         pSrcSurf->Stride() * AlignTo(pSrcSurf->Height(), 2) +
                         ((osrotate.dwSrcY / 2) * pSrcSurf->Stride()) +
                         osrotate.dwSrcX;
            _memwD_EDCreg(EDC_UV_ADDR, dwRegValue);
            
        }
        /* rotate 270, we should config address of first pixsel of last row */
        else
        {
             /* Y address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                        pSrcSurf->Stride() * (pSrcSurf->Height() - 1);
            _memwD_EDCreg(EDC_YRGB_ADDR, dwRegValue);
            
            /* UV address */
            dwRegValue = pSrcSurf->GetPhysicalAddress() + 
                         pSrcSurf->Stride() * pSrcSurf->Height() + 
                         pSrcSurf->Stride() * (pSrcSurf->Height() / 2 - 1);
            _memwD_EDCreg(EDC_UV_ADDR, dwRegValue);
        }
        _memwD_EDCreg(EDC_VIDEO_LN_OFFSET, pSrcSurf->Stride() & YRGB_LN_OFFSET_MASK);
    }                
    else
    {
        DEBUGMSG(GPE_ZONE_HISI, (TEXT("Format not Supported.\n")));
    }

    dwRegValue = (((osrotate.dwSrcW - 1) << VIDEO_SIZE_HRZ_SHIFT) & VIDEO_SIZE_HRZ_MASK) |
                  (((osrotate.dwSrcH - 1) << VIDEO_SIZE_VRT_SHIFT) & VIDEO_SIZE_VRT_MASK);
    _memwD_EDCreg(EDC_VIDEO_SIZE, dwRegValue);
    
    dwRegValue = ((osrotate.dwDstX << VIDEO_X_SHIFT) & VIDEO_X_MASK) | 
                  ((osrotate.dwDstY << VIDEO_Y_SHIFT) & VIDEO_Y_MASK);
    _memwD_EDCreg(EDC_VIDEO_XY, dwRegValue);
    
    dwRegValue = (((osrotate.dwDstW - 1) << SCL_SIZE_HRZ_SHIFT) & SCL_SIZE_HRZ_MASK) |
                   (((osrotate.dwDstH - 1) << SCL_SIZE_VRT_SHIFT) & SCL_SIZE_VRT_MASK);
    _memwD_EDCreg(EDC_SCL_SIZE, dwRegValue);

    /* scaler reg */
    dwRegValue = (((osrotate.dwSrcW - 1) << 17) / (osrotate.dwDstW - 1)) & SCL_PRM_HRZ_MASK;    
    _memwD_EDCreg(EDC_SCL_PRM_HRZ, dwRegValue);

    dwRegValue = (((osrotate.dwSrcH - 1) << 17) / (osrotate.dwDstH - 1)) & SCL_PRM_VRT_MASK;    
    _memwD_EDCreg(EDC_SCL_PRM_VRT, dwRegValue);
    
    //dwControl = dwControl | VIDEO_SCL_EN | dwVideoAngle;
    //dwControl = dwControl | dwVideoAngle; 
    //_memwD_EDCreg(EDC_VIDEO_CTL, dwControl);
    
    if (HIPM_INVALID_CL_ID == m_ClientId)
    {
        TCHAR tcTemp[32];
        wsprintf(tcTemp, TEXT("Disp%d"), GetCurrentProcessId());
        
        ret = HiPM_Register(tcTemp, &m_ClientId);
        
        if (HIPM_STATUS_SUCCESS != ret)
        {
            NKDbgPrintfW(_T("-------HiPM_Register Failed: %d!!!\r\n"), ret);
        }
    }
    
    if (HIPM_INVALID_CL_ID != m_ClientId)
    {
        if (IsNeedLockProfile(osrotate.dwSrcW, osrotate.dwSrcH, 
                              osrotate.dwDstW, osrotate.dwDstH))
        {
            ret = HiPM_SetFreqBlock(m_ClientId, DPM_PROFILE_LEVEL_2);
            
            if (HIPM_STATUS_SUCCESS != ret)
            {
                NKDbgPrintfW(_T("-------HiPM_SetFreqBlock Failed: %d!!!\r\n"), ret);
            }
        }
        else
        {
            ret = HiPM_SetMinProfile(m_ClientId, DPM_PROFILE_LEVEL_2);
            
            if (HIPM_STATUS_SUCCESS != ret)
            {
                NKDbgPrintfW(_T("-------HiPM_SetMinProfile Failed: %d!!!\r\n"), ret);
            }
        }
    }

#if 0
    do
    {
        if(_memrD_EDCreg(EDC_STS) & BAS_VSYNC_MASK)
        {
            break;
        }
    }while (1);
#endif
    
    DWORD dwTimeoutValue = GetTickCount() + 500;
    BOOL bTimeOutFlag = TRUE; 
    do
    {
        if(_memrD_EDCreg(EDC_STS) & BAS_VSYNC_MASK)
        {
            bTimeOutFlag = FALSE;
            break;
        }
    }while (GetTickCount() < dwTimeoutValue);

 /*    
    dwControl = _memrD_EDCreg(EDC_VIDEO_CTL);
    dwControl = dwControl | VIDEO_SCL_EN;
    _memwD_EDCreg(EDC_VIDEO_CTL, dwControl);
    
    dwControl = _memrD_EDCreg(EDC_VIDEO_CTL);
    dwControl = dwControl | VIDEO_ENABLE;
    _memwD_EDCreg(EDC_VIDEO_CTL, dwControl);
*/    
    if (bTimeOutFlag)
    {
        pd->ddRVal = DDERR_GENERIC;
        NKDbgPrintfW(_T("-------Abort: Update Overlay Time out!!!\r\n"));
    }
    else
    {
        dwControl = dwControl | VIDEO_ENABLE | VIDEO_SCL_EN | dwVideoAngle;
        _memwD_EDCreg(EDC_VIDEO_CTL, dwControl);
    
        pd->ddRVal = DD_OK;
    }
    
    DEBUGMSG(GPE_ZONE_HISI, (TEXT("HisiDisp::-UpdateOverlay\r\n")));
    return DDHAL_DRIVER_HANDLED;
}

DWORD
HisiDisp::SetOverlayPosition(LPDDHAL_SETOVERLAYPOSITIONDATA pd)
{
    DWORD   dwRegValue;
    DDGPESurf* pSrcSurf = DDGPESurf::GetDDGPESurf(pd->lpDDSrcSurface);

    if (pSrcSurf != m_pVisibleOverlay)
    {
        pd->ddRVal = DD_OK;
        return DDHAL_DRIVER_HANDLED;
    }

    DDGPESurf * pDestSurf = DDGPESurf::GetDDGPESurf(pd->lpDDDestSurface);

    os.dwDstX = pd->lXPos;
    os.dwDstY = pd->lYPos;

    /* Build a rect with the "logical coordinates" of the overlay */

    RECT NewOverlayRect;

    NewOverlayRect.left  = pd->lXPos;
    NewOverlayRect.right = pd->lXPos + os.dwDstW;

    NewOverlayRect.top    = pd->lYPos;
    NewOverlayRect.bottom = pd->lYPos + os.dwDstH;

    /* Handle any rotation. */
#ifdef ROTATE
    pDestSurf->RotateRectl(reinterpret_cast<RECTL *>(&NewOverlayRect));
#endif

#if 0
    dwRegValue = ((os.dwDstX << VIDEO_X_SHIFT) & VIDEO_X_MASK) | 
                  ((os.dwDstY << VIDEO_Y_SHIFT) & VIDEO_Y_MASK);
#else
    dwRegValue = ((NewOverlayRect.left << VIDEO_X_SHIFT) & VIDEO_X_MASK) | 
                  ((NewOverlayRect.top << VIDEO_Y_SHIFT) & VIDEO_Y_MASK);
#endif

    _memwD_EDCreg(EDC_VIDEO_XY, dwRegValue);   
    pd->ddRVal = DD_OK;

    return DDHAL_DRIVER_HANDLED;
}

#ifdef FULLSCREEN
void HisiDisp::GetFullScreenModeFromReg()
{

    HKEY        hKey;

    if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\GDI\\ROTATION"), 0, 0, &hKey))
    {     
        DWORD dwType = REG_DWORD;
        DWORD dwSize = sizeof(DWORD);
        
        if (ERROR_SUCCESS == RegQueryValueEx(hKey,
                                             TEXT("FULLSCREEN"),
                                             NULL,
                                             &dwType,
                                             (LPBYTE)&gFullScreen,
                                             &dwSize))
        {
            DEBUGMSG(GPE_ZONE_HISI, (TEXT("Success to get full screen reg key.\n")));
            //RETAILMSG(1, (TEXT("Fullscreen reg: %d!\r\n"), gFullScreen));
        }
        else
        {
            RETAILMSG(1, (TEXT("Failed to get full screen reg key.\n")));
        }
        
        if (RegCloseKey(hKey) != ERROR_SUCCESS )
        {
            RETAILMSG(1, (TEXT("Error to close reg key.\n")));
        }        
    }
    else 
    {
        DISPMSG(1, (TEXT("Failed to open full screen reg key.\n")));    
    }
}
#endif

BOOL HisiDisp::IsNeedLockProfile(LONG lWidth, LONG lHeight, LONG lDstWidth, LONG lDstHeight)
{
    DWORD dwSrcArea = 0;
    DWORD dwScaleRate = 0;
    DWORD dwScaleRateThreshold = 10;
    
    if ((0 == lDstWidth * lDstHeight) 
        || (0 == lWidth * lHeight))
    {
        return FALSE;
    }
    
    dwSrcArea = lWidth * lHeight;
    
    dwScaleRate = (dwSrcArea * 10) / (lDstWidth * lDstHeight);
    
    if (m_dwMaxProfile > CPU_FREQ_THRESHOLD)
    {
        if ((m_dwMaxProfile >> 2) < BUS_FREQ_THRESHOLD)
        {
            dwScaleRateThreshold = (LGR_THRESHOLD_LOWPROFILE(dwSrcArea))
                                    ? LOWSCALERATE_LOWPROFILE : HIGHSCALERATE_LOWPROFILE;
        }
        else
        {
            return FALSE;
        }
    }
    
    if (dwScaleRateThreshold < dwScaleRate)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}
#endif
